﻿#light

module DwarfFSharpAsync

open System
open System.Collections.Generic
open System.Runtime.InteropServices
open DwarfConfigurator

[<DllImport(@"CliTools.dll")>]
extern void start()

[<DllImport(@"CliTools.dll")>]
extern double finish()

let processGraphModels(model : DataModel) : DataModel =
    
    //temporary storage for max value for psi array
    let mutable  maxvalind = 0   
    //temporary storage for max value for psi array                     
    let mutable maxval = 0.0
    let mutable tempVal = 0.0 
    // 1. Initialization  delta and psi 
    let numberOfStates = model.hmm.getNumberOfStates()
    for i = 0 to  numberOfStates - 1 do
        model.vit.delta.[0].[i] <- model.hmm.initialStates.[i] * (model.hmm.observationProbabilityMatrix.[i].[model.vit.observationSequence.[0]])
        model.vit.psi.[0].[i] <- 0
    
    // 2. Compute 
    let lengthOfObsSeq = model.vit.getLengthOfObservationSequence()
    let entryForStates t j = 
        //temporary storage for max value for psi array 
        let mutable maxval = 0.0
        let mutable maxvalind = 0
        let tempVal = 0.0
        //finding the maximum
        for i = 0 to numberOfStates - 1 do
            let tempVal = model.vit.delta.[t - 1].[i] * (model.hmm.stateTransitionMatrix.[i].[j])
            if tempVal > maxval then
                maxval <-  tempVal
                maxvalind <- i
        model.vit.delta.[t].[j] <- maxval * (model.hmm.observationProbabilityMatrix.[j].[model.vit.observationSequence.[t]]);
        model.vit.psi.[t].[j] <- maxvalind
    for t = 1 to lengthOfObsSeq - 1 do
        let task i = async {entryForStates t i}
        let tasks = [ for i in 0 .. numberOfStates - 1 -> task(i) ]
        Async.RunSynchronously (Async.Parallel  tasks) |> ignore 

    // 3. Termination 
    model.vit.setProbability(0.0);

    model.vit.sequenceOfState.[lengthOfObsSeq - 1] <- 0
    for  i = 0 to numberOfStates - 1 do
        if (model.vit.delta.[lengthOfObsSeq - 1].[i] > model.vit.getProbability()) then
            model.vit.setProbability(model.vit.delta.[lengthOfObsSeq - 1].[i])
            model.vit.sequenceOfState.[lengthOfObsSeq - 1] <- i
  
    // 4. Path (state sequence) backtracking
    let backtrackingArray = [lengthOfObsSeq - 2 .. -1 .. 0]
    for t in backtrackingArray do
        model.vit.sequenceOfState.[t] <- model.vit.psi.[t + 1].[model.vit.sequenceOfState.[t + 1]]

    model

let main() =
    let args = System.Environment.GetCommandLineArgs()
    let conf = new Configurator()
    let mutable model = conf.configure(args,false)
    model.DWARF_NAME <- "Graph Models, fsharp Async kernel."
    model.DWARF_NAME_OUTPUT <- "Dwarf.FSharp.Async"
    
    start()
    model <- processGraphModels(model)
    let time = finish()
    
    conf.Finish(model,time)  

main()